/*-----------------------------------------------------------------------------------*/
/* Nuvoton Electronics Corporation confidential                                      */
/*                                                                                   */
/* Copyright (c) 2008 by Nuvoton Electronics Corporation                             */
/* All rights reserved                                                               */
/*                                                                                   */
/*-----------------------------------------------------------------------------------*/
/* File Contents:                                                                    */
/*   mass_storage.c                                                                  */
/*                                                                                   */
/* This file contains:                                                               */
/*                                                                                   */
/* Project:                                                                          */
/*                                                                                   */
/* Remark:                                                                           */
/*   1. Support both non-OS and eCos version.                                        */
/*   2. Take care of FMI clock as AHB bus clock.                                     */
/*                                                                                   */
/*-----------------------------------------------------------------------------------*/

#ifdef ECOS 
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "kapi.h"
#include "diag.h"
#include "wbio.h"
#else
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "wblib.h"
#endif

#include "nuc900_reg.h"
#include "nuc900_sic.h"
#include "nuc900_udc.h"
#include "ide.h"


#define CACHE_ON

#ifdef ECOS
#define uprintf		diag_printf
#define ugetchar	diag_getc
#else
#define uprintf		sysprintf
#define ugetchar	sysGetChar
#endif 

#ifdef ECOS
static cyg_handle_t  	thread_handle;
static cyg_thread 		thread;
#define STACKSIZE		(128*1024)
static UINT8            _Statck[STACKSIZE];
#endif

#define SYS_CLOCK			15000000

/*
	ATAPI definition
*/
#define CPU200 0
#define CPU166 1
#define CPU133 2
#define CPU100 3
#define CPU66  4

VOID setATAPIEngineClock(INT nCPUSpeed , INT gEngineClock);

//------------------------- Program -------------------------//
#ifdef ECOS
void usbdExample (cyg_addrword_t tdata)
#else
void usbdExample (VOID)
#endif
{

#if 1
	WB_PLL_T sysClock;

	/* configure system clock */
	sysClock.pll0 = PLL_200MHZ;
	sysClock.pll1 = PLL_133MHZ;
	sysClock.cpu_src = CPU_FROM_PLL0;
	sysClock.ahb_clk = AHB_CPUCLK_1_2;
	sysClock.apb_clk = APB_AHB_1_2;
	sysSetPLLConfig(&sysClock);
#endif	

#ifdef CACHE_ON
	/* configure cache on */
	sysDisableCache();
	sysInvalidCache();
	sysEnableCache(CACHE_WRITE_BACK);	
#endif

#ifndef ECOS
    /* configure Timer0 for FMI library */
	sysSetTimerReferenceClock(TIMER0, SYS_CLOCK);
	sysStartTimer(TIMER0, 100, PERIODIC_MODE);
#endif	
	
#ifdef TEST_HD
	/* initialize ATAPI */
    setATAPIEngineClock(CPU200, ATAPI_CLK_66MHZ);
    uprintf("\nSearch HD, please wait ...\n");
#endif    

	/* initialize FMI (Flash memory interface controller) */
    sicIoctl(SIC_SET_CLOCK, 200000, 0, 0);  /* clock from PLL */
    
    /* initialize USB Device function */
    udcInit();
    
    /* initialize mass storage device */
    udcFlashInit();  
    
   	while (1)
	{
		if (USBModeFlag)
			udcMassBulk();
	}
}

int main (VOID)
{
#ifdef ECOS
	cyg_thread_create(22, usbdExample, 0, "massstorage", _Statck, STACKSIZE, &thread_handle, &thread);
	cyg_thread_resume(thread_handle);
#else
	usbdExample();
#endif	
	
	return 0;
}

#ifndef ECOS
extern unsigned int Image$$ZI$$Limit;
__value_in_regs struct R0_R3 {unsigned heap_base, stack_base, heap_limit, stack_limit;} 
    __user_initial_stackheap(unsigned int R0, unsigned int SP, unsigned int R2, unsigned int SL)
{
    struct R0_R3 config;

    config.heap_base = (unsigned int)&Image$$ZI$$Limit;
    config.stack_base = sysGetSdramSizebyMB()*0x100000; //Stack base;
    //config.stack_base = 0x700000; //Stack base;

/*
To place heap_base directly above the ZI area, use:
    extern unsigned int Image$$ZI$$Limit;
    config.heap_base = (unsigned int)&Image$$ZI$$Limit;
(or &Image$$region_name$$ZI$$Limit for scatterloaded images)

To specify the limits for the heap & stack, use e.g:
    config.heap_limit = SL;
    config.stack_limit = SL;
*/

    return config;
}
#endif

VOID setATAPIEngineClock(INT nCPUSpeed , INT gEngineClock)
{
	/* Set CPU : AHB : ATAPI engine clock speed */
	switch(nCPUSpeed)
	{
		case CPU200:			
			/* CPU:AHB(SDRAM):Engine Clock = 200:100:66(33)	*/
			outpw(REG_CLKSEL, inpw(REG_CLKSEL) & 0x3FF);  // ATAPI engine clock select from PLL0   
		    if (gEngineClock==0)   // 33M
		         outpw(REG_CLKDIV, inpw(REG_CLKDIV) | 0x00500000);  // ATAPI Div=1   PLL0/(5+1)=33M   ATAPI engine clock
		    else
		         outpw(REG_CLKDIV, inpw(REG_CLKDIV) | 0x00200000);  // ATAPI Div=0   PLL0/(2+1)=66M   ATAPI engine clock
		    
		    break;
		    
		case CPU166:
			/* CPU:AHB(SDRAM):Engine Clock = 166:83:66(33) */
			outpw(REG_CLKSEL, (inpw(REG_CLKSEL) & 0x3ff) | 0x400);  // ATAPI engine clock select from PLL1   
			if (gEngineClock==0)   // 33M
		         outpw(REG_CLKDIV, inpw(REG_CLKDIV) | 0x00100000);  // ATAPI Div=1   PLL1/(1+1)=33M   ATAPI engine clock
		    else
		         outpw(REG_CLKDIV, inpw(REG_CLKDIV) & 0xff0fffff);  // ATAPI Div=0   PLL1/(0+1)=66M   ATAPI engine clock
		    
		    break;
		
		case CPU133:
			/* CPU:AHB(SDRAM):Engine Clock = 133:133:66(33) */
			outpw(REG_CLKSEL, inpw(REG_CLKSEL) & 0x3FF);  // ATAPI engine clock select from PLL0   
		    if (gEngineClock==0)   // 33M
		         outpw(REG_CLKDIV, 0x00300000);  // ATAPI Div=1   PLL0/(3+1)=33M   ATAPI engine clock
		    else
		         outpw(REG_CLKDIV, 0x00100000);  // ATAPI Div=0   PLL0/(1+1)=66M   ATAPI engine clock
		    
		    break;
		    
		case CPU100:		
			/* CPU:AHB(SDRAM):Engine Clock = 100:100:66(33) */
			outpw(REG_CLKSEL, (inpw(REG_CLKSEL) & 0x3ff) | 0x400);  // ATAPI engine clock select from PLL1   
		    if (gEngineClock==0)   // 33M
		         outpw(REG_CLKDIV, 0x00100000);  // ATAPI Div=1   PLL1/(1+1)=33M   ATAPI engine clock
		    else
		         outpw(REG_CLKDIV, 0x00000000);  // ATAPI Div=0   PLL1/(0+1)=66M   ATAPI engine clock
		    
		    break;
		    
		case CPU66:			
			/* CPU:AHB(SDRAM):Engine Clock = 66:66:66(33) */
		    outpw(REG_CLKSEL, inpw(REG_CLKSEL) & 0x3FF);  // ATAPI engine clock select from PLL0   
		    if (gEngineClock==0)   // 33M
		         outpw(REG_CLKDIV, 0x00100000);  // ATAPI Div=1   PLL0/(1+1)=33M   ATAPI engine clock
		    else
		         outpw(REG_CLKDIV, 0x00000000);  // ATAPI Div=0   PLL0/(0+1)=66M   ATAPI engine clock
		    
		    break; 
	}
}
